package com.mall.common.hibernate.search;

import java.io.File;
import java.io.IOException;
import java.util.Properties;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.lucene.store.FSDirectory;
import org.hibernate.search.SearchException;
import org.hibernate.search.spi.BuildContext;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.DirectoryProviderHelper;
import org.hibernate.search.store.FSDirectoryProvider;

/**
 * #Hibernate Configuration配置文件
 * hibernate.search.default.directory_provider = 包名.ExFSDirectoryProvider
 * #放于应用/lucene/index包下
 * hibernate.search.default.indexBase = classpath:/lucene/index
*/
public class ExFSDirectoryProvider implements DirectoryProvider<FSDirectory> {
    
    private static final String CLASSPATH = "classpath:";
    private Logger log =  LoggerFactory.getLogger(ExFSDirectoryProvider.class);
    
    private FSDirectory directory;
    private String indexName;
    
    @Override
    public FSDirectory getDirectory() {
        return this.directory;
    }
    

    @Override
    public void stop() {
        try {
            this.directory.close();
        } catch (Exception e) {
        	log.warn("can not close directory", e);
        }
    }
    
    @Override
    public void initialize(String directoryProviderName, Properties properties, BuildContext context) {
        boolean manual = context.getIndexingStrategy().equals("manual");
        /**
         * 主要改写了这个方法 File indexDir = org.hibernate.search.store.impl.DirectoryProviderHelper.DirectoryProviderHelper.getVerifiedIndexDir(directoryProviderName, properties, !(manual));
         */
        File indexDir = getVerifiedIndexDir(directoryProviderName, properties, !(manual));

        try{
            //TODO 每次重启动服务器时，将旧的索引文件删除
            for(File file : indexDir.listFiles()){
                FileUtils.forceDelete(file);
            }
        }catch (Exception e){//
            log.warn("重启服务后，旧的索引文件删除失败",e);
        }

        try {
        	//返回抽象路径名的规范路径名字符串。
        	this.indexName = indexDir.getCanonicalPath();
        	this.directory = DirectoryProviderHelper.createFSIndex(indexDir, properties);
        } catch (IOException e) {
        	throw new SearchException("Unable to initialize index: " + directoryProviderName, e);
        }
    }
    
    private File getVerifiedIndexDir(String annotatedIndexName, Properties properties, boolean verifyIsWritable) {
    	String indexBase = properties.getProperty("indexBase", ".");
    	/**
    	 * 得到存索引的路径.至于放在哪个位置就由你自己操作
    	 */
    	indexBase = getIndexBaseByIsRelative(indexBase);
    	String indexName = properties.getProperty("indexName", annotatedIndexName);
    	File baseIndexDir = new File(indexBase);
    	makeSanityCheckedDirectory(baseIndexDir, indexName, verifyIsWritable);
    	File indexDir = new File(baseIndexDir, indexName);
    	makeSanityCheckedDirectory(indexDir, indexName, verifyIsWritable);
    	return indexDir;
    }
    
    private String getIndexBaseByIsRelative(String indexBase) {
        if( indexBase.contains(CLASSPATH) ){
            String path = ExFSDirectoryProvider.class.getResource("/").getPath();
//            path = path.substring( path.indexOf("/") + 1 );
            indexBase = path + indexBase.substring( indexBase.indexOf(":") + 1 );
            return indexBase;
        } else {
            return indexBase;
        }
    }

    //验证目录存在并且是可写，或创建它如果不存在.
    private void makeSanityCheckedDirectory(File directory, String indexName, boolean verifyIsWritable) {
    	if (!(directory.exists())) {
    		log.info("目录不存在,创建新目录:" + directory.getAbsolutePath() );
			if (directory.mkdirs()) {
			    return;
			}
			throw new SearchException(new StringBuilder().append("Unable to create index directory: ").append(directory.getAbsolutePath()).append(" for index ").append(indexName).toString());
    	}

    	if (!(directory.isDirectory())) {
    		throw new SearchException(new StringBuilder().append("Unable to initialize index: ").append(indexName).append(": ").append(directory.getAbsolutePath()).append(" is a file.").toString());
    	}

    	if ((verifyIsWritable) && (!(directory.canWrite()))) {
    		throw new SearchException(new StringBuilder().append("Cannot write into index directory: ").append(directory.getAbsolutePath()).append(" for index ").append(indexName).toString());
    	}
    }

    public boolean equals(Object obj) {
    	if (obj == this) {
    		return true;
    	}
    	if ((obj == null) || (!(obj instanceof FSDirectoryProvider))) {
    		return false;
    	}
    	return this.indexName.equals(((ExFSDirectoryProvider)obj).indexName);
    }

    public int hashCode() {
    	int hash = 11;
    	return (37 * hash + this.indexName.hashCode());
    }


	@Override
	public void start() {
	}
}
